package com.company.cloud.point.modules.mgr.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.company.cloud.acct.modules.api.constant.AcctOpTypeEnum;
import com.company.cloud.acct.modules.api.constant.AcctTypeEnum;
import com.company.cloud.acct.modules.api.request.AcctOpRequest;
import com.company.cloud.acct.modules.app.service.AcctOpService;
import com.company.cloud.common.asserts.ValidatorUtils;
import com.company.cloud.common.bean.LoginSimpleUserInfo;
import com.company.cloud.common.constant.BaseConstant;
import com.company.cloud.common.constant.BaseReturnEnum;
import com.company.cloud.common.exception.BusinessException;
import com.company.cloud.common.utils.LocalDateTimeUtils;
import com.company.cloud.point.constant.PointEventEnum;
import com.company.cloud.point.modules.api.request.PointEventParam;
import com.company.cloud.point.modules.app.controller.req.PointProcessParam;
import com.company.cloud.point.modules.base.entity.PointRuleConfig;
import com.company.cloud.point.modules.base.entity.PointRuleGrantLog;
import com.company.cloud.point.modules.base.service.PointRuleConfigService;
import com.company.cloud.point.modules.base.service.PointRuleGrantLogService;
import com.company.cloud.point.modules.cache.models.PointRuleConfigModel;
import com.company.cloud.point.modules.cache.utils.PointTaskIdUtils;
import com.company.cloud.point.modules.mgr.controller.req.PointRuleConfigQuery4PageParam;
import com.company.cloud.point.modules.mgr.controller.req.PointRuleConfigSaveParam;
import com.company.cloud.point.modules.mgr.controller.req.PointRuleConfigUpdateParam;
import com.company.cloud.point.modules.mgr.service.PointRuleConfigMgrService;
import com.company.common.server.constant.AppEventEnum;
import com.company.common.server.constant.IRelBusiType;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Log4j2
@Service
public class PointRuleConfigMgrServiceImpl implements PointRuleConfigMgrService {

    @Autowired
    private PointRuleConfigService pointRuleConfigService;
    @Autowired
    private PointRuleGrantLogService pointRuleGrantLogService;
    @Autowired
    private AcctOpService acctOpService;

    @Override
    public IPage<PointRuleConfigModel> query(PointRuleConfigQuery4PageParam params, LoginSimpleUserInfo userInfo) {
        return null;
    }

    @Override
    public void save(PointRuleConfigSaveParam params, LoginSimpleUserInfo userInfo) {
        ValidatorUtils.validate(params);
        int count = pointRuleConfigService.count(new QueryWrapper<PointRuleConfig>()
                .eq("company_no", params.getCompanyNo())
                .eq("event_no", params.getEventNo())
                .eq("rows_state", BaseConstant.EnabledEnum.ENABLED.getCode())
        );
        if (count > 0) {
            throw new BusinessException("同一事件只能有一个配置信息");
        }
        PointRuleConfig entity = new PointRuleConfig();
        if (StringUtils.isEmpty(params.getRuleNo())) {
            entity.setRuleNo(PointTaskIdUtils.getPointRuleConfigId());
        } else {
            entity.setRuleNo(params.getRuleNo());
        }
        entity.setCompanyNo(params.getCompanyNo());
        entity.setRuleType(params.getRuleType());
        entity.setRuleName(params.getRuleName());
        entity.setRewardVal(params.getRewardVal());
        entity.setEventNo(params.getEventNo());
        if (!CollectionUtils.isEmpty(params.getRewardCondition())) {
            entity.setRewardCondition(JSON.toJSONString(params.getRewardCondition()));
        }
        entity.addCreateParam(userInfo);
        entity.addEditParam(userInfo);
        pointRuleConfigService.save(entity);
    }

    @Override
    public void update(PointRuleConfigUpdateParam params, LoginSimpleUserInfo userInfo) {
        ValidatorUtils.validate(params);
        PointRuleConfig entity = pointRuleConfigService.getById(params.getRuleNo());
        if (entity == null || BaseConstant.EnabledEnum.DISABLED.getCode().equals(entity.getRowsState())) {
            throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
        }
        entity.setRuleName(params.getRuleName());
        entity.setRewardVal(params.getRewardVal());
        if (!CollectionUtils.isEmpty(params.getRewardCondition())) {
            entity.setRewardCondition(JSON.toJSONString(params.getRewardCondition()));
        }
        entity.addEditParam(userInfo);
        pointRuleConfigService.updateById(entity);

    }

    @Override
    public void del(String id, LoginSimpleUserInfo userInfo) {
        PointRuleConfig entity = pointRuleConfigService.getById(id);
        if (entity == null || BaseConstant.EnabledEnum.DISABLED.getCode().equals(entity.getRowsState())) {
            throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
        }
        entity.setRowsState(BaseConstant.EnabledEnum.DISABLED.getCode());
        entity.addEditParam(userInfo);
        pointRuleConfigService.updateById(entity);
    }


    @Transactional
    @Override
    public void pointEventProcess(PointEventParam param, LoginSimpleUserInfo userInfo) {
        log.debug("++++++ 积分事件结算:" + JSON.toJSONString(param));
        PointRuleConfig entity = pointRuleConfigService.getOne(
                new QueryWrapper<PointRuleConfig>()
                        .eq("company_no", param.getCompanyNo())
                        .eq("event_no", param.getEventNo())
                        .eq("rows_state", BaseConstant.EnabledEnum.ENABLED.getCode())
        );

        if (entity == null) {
            log.debug("++++++ 积分事件配置不存在");
            return;
        }
        if (AppEventEnum.User_Register.getCode().equals(entity.getEventNo())) {
            this.event_UserReg(entity, param, userInfo);
        }
    }

    @Override
    public void process(PointProcessParam param, LoginSimpleUserInfo userInfo) {
        ValidatorUtils.validate(param);
        PointRuleConfig entity = pointRuleConfigService.getOne(
                new QueryWrapper<PointRuleConfig>()
                        .eq("company_no", param.getCompanyNo())
                        .eq("event_no", param.getEventNo())
                        .eq("rows_state", BaseConstant.EnabledEnum.ENABLED.getCode())
        );
        if (entity == null) {
            log.debug("++++++ 积分事件配置不存在");
            return;
        }

        if (PointEventEnum.User_SignIn.getCode().equals(param.getEventNo())) {
            this.event_sign(entity, param, userInfo);
        }

        if (PointEventEnum.User_Share.getCode().equals(param.getEventNo())) {
            this.event_share(entity, param, userInfo);
        }

        if (PointEventEnum.User_CompanySign.getCode().equals(param.getEventNo())) {
            this.event_company_sign(entity, param, userInfo);
        }

        if (PointEventEnum.User_UploadImg.getCode().equals(param.getEventNo())) {
            this.event_uploadImg(entity, param, userInfo);
        }

        if (PointEventEnum.User_Questionnaire.getCode().equals(param.getEventNo())) {
            this.event_wz(entity, param, userInfo);
        }
    }


    /**
     * 用户每日签到事件
     */
    private void event_sign(PointRuleConfig entity, PointProcessParam param, LoginSimpleUserInfo userInfo) {
        List<PointRuleGrantLog> list = pointRuleGrantLogService.list(new QueryWrapper<PointRuleGrantLog>()
                .eq("user_id", param.getUserId())
                .eq("event_no", param.getEventNo())
                .eq("DATE_FORMAT(cdt,'%Y-%m-%d')", DateUtil.today())
        );
        if (CollUtil.isNotEmpty(list)) {
            throw new BusinessException("JF001", "用户今日已签到");
        }
        this._p(entity, param, userInfo, "用户每日签到送积分", "用户每日签到");
    }

    /**
     * 用户分享事件
     */
    private void event_share(PointRuleConfig entity, PointProcessParam param, LoginSimpleUserInfo userInfo) {
        int num = pointRuleGrantLogService.count(new QueryWrapper<PointRuleGrantLog>()
                .eq("user_id", param.getUserId())
                .eq("event_no", param.getEventNo())
                .eq("rel_id_type", param.getRelIdType())
                .eq("rel_id", param.getRelId())
                .eq("DATE_FORMAT(cdt,'%Y-%m-%d')", DateUtil.today())
        );
        if (num > 20) {
            throw new BusinessException("JF002", "每日分享上线20次");
        }
        this._p(entity, param, userInfo, "用户分享送积分", "用户分享");
    }

    /**
     * 用户画廊打卡事件
     */
    private void event_company_sign(PointRuleConfig entity, PointProcessParam param, LoginSimpleUserInfo userInfo) {
        List<PointRuleGrantLog> list = pointRuleGrantLogService.list(new QueryWrapper<PointRuleGrantLog>()
                .eq("user_id", param.getUserId())
                .eq("event_no", param.getEventNo())
                .eq("rel_id_type", param.getRelIdType())
                .eq("rel_id", param.getRelId())
                .eq("DATE_FORMAT(cdt,'%Y-%m-%d')", DateUtil.today())
        );

        if (CollUtil.isNotEmpty(list)) {
            throw new BusinessException("JF003", "每日已画廊打卡");
        }
        this._p(entity, param, userInfo, "用户画廊打卡送积分", "用户画廊打卡");
    }

    /**
     * 用户上传一张图片事件
     */
    private void event_uploadImg(PointRuleConfig entity, PointProcessParam param, LoginSimpleUserInfo userInfo) {
        int num = pointRuleGrantLogService.count(new QueryWrapper<PointRuleGrantLog>()
                .eq("user_id", param.getUserId())
                .eq("event_no", param.getEventNo())
                .eq("DATE_FORMAT(cdt,'%Y-%m-%d')", DateUtil.today())
        );
        if (num > 20) {
            throw new BusinessException("JF004", "每日上传图片次数超20次");
        }

        this._p(entity, param, userInfo, "用户上传图片送积分", "用户上传图片");

    }

    /**
     * 用户填写调查问卷事件
     */
    private void event_wz(PointRuleConfig entity, PointProcessParam param, LoginSimpleUserInfo userInfo) {
        List<PointRuleGrantLog> list = pointRuleGrantLogService.list(new QueryWrapper<PointRuleGrantLog>()
                .eq("user_id", param.getUserId())
                .eq("event_no", param.getEventNo())
                .eq("rel_id_type", param.getRelIdType())
                .eq("rel_id", param.getRelId())
                .eq("DATE_FORMAT(cdt,'%Y-%m-%d')", DateUtil.today())
        );
        if (CollUtil.isNotEmpty(list)) {
            throw new BusinessException("JF005", "用户已填写问卷");
        }
        this._p(entity, param, userInfo, "用户填写调查问卷送积分", "用户填写调查问卷");
    }

    /**
     * 用户购买商品事件
     */
    private void event_shop(PointRuleConfig entity, PointProcessParam param, LoginSimpleUserInfo userInfo) {

    }


    private void _p(PointRuleConfig entity, PointProcessParam param, LoginSimpleUserInfo userInfo, String relBizName, String memo) {
        PointRuleGrantLog pointRuleGrantLog = new PointRuleGrantLog();
        pointRuleGrantLog.setCompanyNo(entity.getCompanyNo());
        pointRuleGrantLog.setRuleNo(entity.getRuleNo());
        pointRuleGrantLog.setEventNo(entity.getEventNo());
        pointRuleGrantLog.setRewardVal(entity.getRewardVal());
        pointRuleGrantLog.setUserId(param.getUserId());
        pointRuleGrantLog.setState(BaseConstant.YNEnum.YES.getCode());
        pointRuleGrantLog.setRelIdType(param.getRelIdType());
        pointRuleGrantLog.setRelId(param.getRelId());
        pointRuleGrantLog.addCreateParam(userInfo);
        pointRuleGrantLog.addEditParam(userInfo);
        pointRuleGrantLogService.save(pointRuleGrantLog);

        AcctOpRequest acctOpRequest = new AcctOpRequest();
        acctOpRequest.setUserId(param.getUserId());
        acctOpRequest.setType(AcctTypeEnum.Point_Acct.getCode());
        acctOpRequest.setIsAcctDetail(BaseConstant.YNEnum.YES.getCode());
        acctOpRequest.setOpType(AcctOpTypeEnum.Add_Acct.getCode());
        acctOpRequest.setRelObjType(IRelBusiType.Point_Rule_Grant_ObjType);
        acctOpRequest.setRelObjNo(pointRuleGrantLog.getId().toString());
        acctOpRequest.setFundOp(new BigDecimal(entity.getRewardVal()));
        acctOpRequest.setOverdueFundDate(LocalDateTimeUtils.plusDay_yyyyMMddHHmmss(365));
        acctOpRequest.setRelBizName(relBizName);
        acctOpRequest.setBusiType("积分");
        acctOpRequest.setRelDate(LocalDateTimeUtils.format_yyyyMMddHHmmss());
        acctOpRequest.setMemo(memo);
        acctOpRequest.setOpUserId(userInfo.getId());
        acctOpRequest.setOpIp(userInfo.getIp());
        try {
            acctOpService.acctOp(acctOpRequest, userInfo);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 用户注册事件
     */
    private void event_UserReg(PointRuleConfig entity, PointEventParam param, LoginSimpleUserInfo userInfo) {
        int count = pointRuleGrantLogService.count(new QueryWrapper<PointRuleGrantLog>()
                .eq("user_id", param.getUserId())
                .eq("event_no", param.getEventNo())
        );
        if (count > 0) {
            throw new BusinessException("积分已经发放，不能重复领取");
        }
        PointRuleGrantLog pointRuleGrantLog = new PointRuleGrantLog();
        pointRuleGrantLog.setCompanyNo(entity.getCompanyNo());
        pointRuleGrantLog.setRuleNo(entity.getRuleNo());
        pointRuleGrantLog.setEventNo(entity.getEventNo());
        pointRuleGrantLog.setRewardVal(entity.getRewardVal());
        pointRuleGrantLog.setUserId(param.getUserId());
        pointRuleGrantLog.setState(BaseConstant.YNEnum.YES.getCode());
        pointRuleGrantLog.addCreateParam(userInfo);
        pointRuleGrantLog.addEditParam(userInfo);
        pointRuleGrantLogService.save(pointRuleGrantLog);

        AcctOpRequest acctOpRequest = new AcctOpRequest();
        acctOpRequest.setUserId(param.getUserId());
        acctOpRequest.setType(AcctTypeEnum.Point_Acct.getCode());
        acctOpRequest.setIsAcctDetail(BaseConstant.YNEnum.YES.getCode());
        acctOpRequest.setOpType(AcctOpTypeEnum.Add_Acct.getCode());
        acctOpRequest.setRelObjType(IRelBusiType.Point_Rule_Grant_ObjType);
        acctOpRequest.setRelObjNo(pointRuleGrantLog.getId().toString());
        acctOpRequest.setFundOp(new BigDecimal(entity.getRewardVal()));
        acctOpRequest.setOverdueFundDate(LocalDateTimeUtils.plusDay_yyyyMMddHHmmss(365));
        acctOpRequest.setRelBizName("注册送积分");
        acctOpRequest.setBusiType("积分");
        acctOpRequest.setRelDate(LocalDateTimeUtils.format_yyyyMMddHHmmss());
        acctOpRequest.setMemo("积分");
        acctOpRequest.setOpUserId(param.getOpUserId());
        acctOpRequest.setOpIp(param.getOpIp());
        try {
            acctOpService.acctOp(acctOpRequest, userInfo);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }


}
